package club.lemos.sso.web.rest;

import club.lemos.common.pojo.CommonResult;
import club.lemos.sso.config.security.common.LopUserDetails;
import club.lemos.sso.config.security.jwt.JwtTokenUtil;
import club.lemos.sso.domain.LopAuthenticationRequest;
import club.lemos.sso.domain.LopAuthenticationResponse;
import club.lemos.sso.domain.LopUserRequest;
import club.lemos.sso.service.FreemarkerMailService;
import club.lemos.sso.service.LopUserService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.mobile.device.Device;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 创建 token 和 获取刷新token
 */
@RestController
public class TokenRestController {

    @Value("${jwt.header}")
    private String tokenHeader;

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private JwtTokenUtil jwtTokenUtil;

    @Resource(name = "lopUserDetailsServiceImpl")
    private UserDetailsService userDetailsService;

    @Resource
    private LopUserService lopUserService;

    @Resource
    private FreemarkerMailService freemarkerMailService;

    /**
     * 需要发送 json 请求
     *
     * @param jwtAuthentication
     * @param device
     * @return
     * @throws AuthenticationException
     */
    @RequestMapping(value = "${jwt.route.authentication.path}", method = RequestMethod.POST)
    public ResponseEntity<?> createAuthenticationToken(@RequestBody LopAuthenticationRequest jwtAuthentication, Device device) throws AuthenticationException {

        //Perform the security
        //认证失败进行 entryPoint,认证成功 continue
        final Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        jwtAuthentication.getUsername(),
                        jwtAuthentication.getPassword()
                )
        );

        SecurityContextHolder.getContext().setAuthentication(authentication);

        // Reload password post-security so we can generate token
        final UserDetails userDetails = userDetailsService.loadUserByUsername(jwtAuthentication.getUsername());
        final String token = jwtTokenUtil.generateToken(userDetails, device);

        // Return the token
        return ResponseEntity.ok(new LopAuthenticationResponse(token));
    }

    /**
     * 刷新过期时间
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "${jwt.route.authentication.refresh}", method = RequestMethod.POST)
    public ResponseEntity<?> refreshAndGetAuthenticationToken(HttpServletRequest request) {
        String token = request.getHeader(tokenHeader);
        //解析 token进行验证
        String username = jwtTokenUtil.getUsernameFromToken(token);
        LopUserDetails user = (LopUserDetails) userDetailsService.loadUserByUsername(username);

        /*
         * 查询数据库进行验证,判断是否可刷新
         */
        if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())) {
            String refreshedToken = jwtTokenUtil.refreshToken(token);
            return ResponseEntity.ok(new LopAuthenticationResponse(refreshedToken));
        } else {
            return ResponseEntity.badRequest().body(null);
        }
    }

    /**
     * 用户注册
     */
    @RequestMapping(value = "/userRegister", method = RequestMethod.POST)
    private CommonResult userRegister(@RequestBody LopUserRequest userRequest) {
        CommonResult commonResult = lopUserService.userRegister(userRequest);
        return commonResult;
    }

    /**
     * 发送邮箱
     */
    @RequestMapping(value = "/sendMail", method = RequestMethod.POST)
    private CommonResult sendMail(@RequestBody String param) {

        Map<String, String> map = JSON.parseObject(param, new TypeReference<Map<String, String>>() {
        });
        String username = map.get("username");
        String emailAddress = map.get("email");

        //生成一个验证码
        String validataCode = UUID.randomUUID().toString();
        lopUserService.sendActiveCode(validataCode, username);

        //发送邮件
        String templateName = "mail-template.ftl";
        Map<String, String> content = new HashMap<String, String>();
        content.put("name", username);
        content.put("activeCode", validataCode);
        String subject = "LEMOS.CLUB";
        try {
            freemarkerMailService.sendMail(templateName, emailAddress, subject, content);
        } catch (Exception e) {
            e.printStackTrace();
            return CommonResult.build(500, "邮件未发送");
        }
        return CommonResult.ok();
    }

    /**
     * 验证和激活邮箱
     */
    @RequestMapping(value = "/mail/active/{username}/{activeCode}", method = RequestMethod.GET)
    private ModelAndView verifyAndActiveUser(@PathVariable String username, @PathVariable String activeCode, ModelAndView modelAndView, HttpServletRequest request) {
        CommonResult result = lopUserService.verifyAndActiveUser(true, activeCode, username);
        if (result.getStatus() == 400) {
            modelAndView.addObject("msg", "对不起，您的激活码不正确。");
        } else {
            modelAndView.addObject("msg", "恭喜！成功激活。请点击右边的链接直接登录!");
            modelAndView.addObject("redirectUrl", request.getContextPath() + "/login");
        }
        modelAndView.addObject("username", username);
        modelAndView.setViewName("mail-msg");
        return modelAndView;
    }

}
